using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Xml;
using System.Web;
using System.Web.UI;

/*	-----------------------------------------------------------------------	
	Copyright:	umlungu consulting (Pty) ltd
	Author:		Alan Benington	
	Started:	2005-05-15	
	Status:		release	
	Version:	2.0.0
	Buidl:		20070524
	License:	GNU General Public License
	-----------------------------------------------------------------------	*/
	
/*	-----------------------------------------------------------------------	
	Development Notes:
	==================
	20070524:	Modification for .Net 2.0
	-----------------------------------------------------------------------	*/
	
namespace umlungu.engineX.webserviceX {
	/// <summary>
	/// The x_method class...
	/// </summary>
	public class x_method {
		#region Invisible properties
		/// <summary>
		/// Local properties
		/// </summary>
		private string name;
		private x_service xServ;
		private XmlNode xDef;
		private string xMod;
		private string xType;
		private SqlCommand xCmd;
		private StringBuilder csvData;
		private string csvDataLine;
		
		private const string errCreate	= "error_create";
		private const string errLoad	= "error_load";
		#endregion

		#region Visible properties
		private bool isValid = false;
		/// <summary>Validation flag</summary>
		/// <value>'true' if validation is ok, else 'false'</value>
		public bool IsValid			{ get {	return isValid; }				set { isValid = value;	}}
		private bool isLoaded = false;
		/// <summary>Method load flag</summary>
		/// <value>'true' if method is loaded ok</value>
		public bool IsLoaded		{ get {	return isLoaded; }				set { isLoaded = value;	}}
		private bool reqValidation = false;
		/// <summary>Require validation flag</summary>
		/// <value>'true' if the method requires validation</value>
		public bool ReqValidation	{ get {	return(RequireValidation()); }	set { reqValidation = value; }}
		private XmlDocument xDoc;
		/// <summary>Result document</summary>
		/// <value>XmlDocument containing result</value>
		public XmlDocument Result	{ get {	return xDoc; }}
		private string xDSN;
		/// <summary>Database connection</summary>
		/// <value>Current database connection string (defined in web.config)</value>
		public string DSN	{	get {	return xDSN; }
								set { if (ConfigurationManager.AppSettings[value] != null)
										xDSN = ConfigurationManager.AppSettings[value];	
								}
							}
		/// <summary>Load Error flag</summary>
		/// <value>'true' if error on loading method</value>
		public bool LoadError { get { return(!isLoaded); } }
		/// <summary>Error document</summary>
		/// <value>XmlDocument containing error</value>
		public XmlDocument Error { get { return(xDoc); }}
		/// <summary>Current method</summary>
		/// <value>XmlElement of currently loaded method, else null</value>
		public XmlElement Method { get { return(isLoaded? (XmlElement)xDef : null); }}
		/// <summary>Current module</summary>
		/// <value>XmlElement of module containing currently loaded method, else null</value>
		public XmlElement Module { get { return(isLoaded? (XmlElement)xDef.ParentNode : null); }}
		#endregion

		#region Constructors/Destructors
		/// <overloads>Constructor</overloads>
		/// <summary>description</summary>
		/// <param name="app">Web service http application</param>
		/// <param name="method">Name of the method</param>
		/// <param name="ServiceName">Name of the service</param>
		public x_method(HttpApplicationState app, string method, string ServiceName) {
			try {
				setDefaults(app, ServiceName);
				loadMethod(method);
			} catch (Exception exc) {
				throw(new x_exception(errCreate, String.Concat(exc.Source, "::", exc.Message, ":", exc.StackTrace)));
			}
		}
		/// <summary>description</summary>
		/// <param name="method">Name of the method</param>
		/// <param name="service">Name of the service</param>
		public x_method(string service, string method) {
			try {
				setDefaults(service);
				loadMethod(method);
			} catch (Exception exc) {
				throw(new x_exception(errCreate, String.Concat(exc.Source, "::", exc.Message, ":", exc.StackTrace)));
			}
		}
		/// <summary>description</summary>
		/// <param name="service">Name of the service</param>
		public x_method(string service) {
			try {
				setDefaults(service);
			} catch (Exception exc) {
				throw(new x_exception(errCreate, String.Concat(exc.Source, "::", exc.Message, ":", exc.StackTrace)));
			}
		}
		/// <summary>description</summary>
		/// <param name="app">Web service http application</param>
		/// <param name="ServiceName">Name of the service</param>
		public x_method(HttpApplicationState app, string ServiceName) {
			try {
				setDefaults(app, ServiceName);
			} catch (Exception exc) {
				throw(new x_exception(errCreate, String.Concat(exc.Source, "::", exc.Message, ":", exc.StackTrace)));
			}
		}
		/// <summary>description</summary>
		/// <param name="app">Web service http application</param>
		/// <param name="resultDoc">Result document</param>
		/// <param name="ServiceName">Name of the service</param>
		public x_method(HttpApplicationState app, XmlDocument resultDoc, string ServiceName) {
			try {
				setDefaults(xDoc, app, ServiceName);
			} catch (Exception exc) {
				throw(new x_exception(errCreate, String.Concat(exc.Source, "::", exc.Message, ":", exc.StackTrace)));
			}
		}
		#endregion

		#region Public methods
		/// <overloads>Loads the web service method from the xml definition</overloads>
		/// <summary>
		/// Loads by name
		/// </summary>
		/// <param name="method">method name</param>
		public bool Load(string method) {
			try {
				loadMethod(method);
			} catch (Exception exc) {
				throw(new x_exception(errLoad, String.Concat(exc.Source, "::", exc.Message, ":", exc.StackTrace)));
			}
			return(isLoaded);
		}
		/// <summary>
		/// Validates first then loads by name
		/// </summary>
		/// <param name="method">method name</param>
		/// <param name="token">authentication token</param>
		public bool Load(string method, string token) {
			try {
				loadMethod(method, token);
			} catch (Exception exc) {
				throw(new x_exception(errLoad, String.Concat(exc.Source, "::", exc.Message, ":", exc.StackTrace)));
			}
			return(isLoaded);
		}
		
		/// <overloads>Calls some data source (stored procedures, other methods, etc)</overloads>
		/// <summary>
		/// Calls a defined method by Load
		/// </summary>
		/// <param name="args">Method arguments</param>
		public XmlDocument Call(params string[] args) {
			return(Call(xDef, args));
		}
		/// <summary>
		/// Calls a defined method by Load, into a Result document
		/// </summary>
		/// <param name="result">Result document</param>
		/// <param name="args">Method arguments</param>
		public XmlDocument Call(XmlDocument result, params string[] args) {
			return(Call(result, xDef, args));
		}
		/// <summary>
		/// Calls a method defined by an XmlNode
		/// </summary>
		/// <param name="thisdef">The node that defines the method</param>
		/// <param name="args">Method arguments</param>
		public XmlDocument Call(XmlNode thisdef, params string[] args) {
			XmlDocument call;
			string thistype = xServ.GetCall(thisdef.SelectSingleNode("@name").InnerText);
			switch(thistype) {
				case "sproc":	
					call = CallProcedure(thisdef, args);
					break;
				case "methods":	
					call = CallMethods(thisdef, args);
					break;
				default:
					call = null;
					break;
			}
			return(call);
		}
		/// <summary>
		/// Calls a method defined by an XmlNode, into a Result document
		/// </summary>
		/// <param name="result">Result document</param>
		/// <param name="thisdef">The node that defines the method</param>
		/// <param name="args">Method arguments</param>
		public XmlDocument Call(XmlDocument result, XmlNode thisdef, params string[] args) {
			XmlDocument call;
			string thistype = xServ.GetCall(thisdef.SelectSingleNode("@name").InnerText);
			switch(thistype) {
				case "sproc":	
					call = CallProcedure(result, thisdef, args);
					break;
				case "methods":	
					call = CallMethods(result, thisdef, args);
					break;
				default:
					call = null;
					break;
			}
			return(call);
		}
		
		/// <overloads>Calls a stored procedure</overloads>
		/// <summary>
		/// Calls a stored procedure
		/// </summary>
		public XmlDocument CallProcedure(XmlNode def, params string[] args) {
			XmlDocument thisDoc = new XmlDocument();
			thisDoc.LoadXml(xServ.GetReturn(def.SelectSingleNode("@name").InnerText));
			return(CallProcedure(thisDoc, def, args));
		}
		/// <summary>
		/// Calls a stored procedure
		/// </summary>
		public XmlDocument CallProcedure(XmlDocument ResultDoc, XmlNode def, params string[] args) {
			string procname = xServ.GetProcedure(def);
			bool wantreturn = true;
			if (!isLoaded)
				return(ResultDoc);
			using (SqlConnection xdb = new SqlConnection(xDSN)) {
				try {
					xdb.Open();
					xCmd = new SqlCommand(procname, xdb);
					xCmd.CommandType = CommandType.StoredProcedure;
					
					// Set timeout
					if (def.SelectSingleNode("@timeout") != null)
						xCmd.CommandTimeout = System.Convert.ToInt32(def.SelectSingleNode("@timeout").InnerText);
					
					// Add the 'Result' parameter to get the return value of the stored proc
					if (def.SelectSingleNode("call[@type='sproc'][@return='yes']") != null)
						AddSqlPar();
					else
						wantreturn = false;
					
					// Add explicitly defined parameters
					XmlElement xPar;
					XmlNodeList xDefList = def.SelectNodes("call[@type='sproc']/input/parameter");
					bool thisok, isok = true;
					for (int i=0; i < xDefList.Count; i++) {
						xPar = (XmlElement)xDefList.Item(i);
						if (xPar.GetAttribute("nothing") == "yes" && args[i] == "")
							throw new Exception("Cannot have empty value");
						switch (xPar.GetAttribute("type")) {
							case "xhtml":
								if (xPar.SelectSingleNode("@length") == null)
									throw new Exception(String.Concat("Definition must specify length for xhtml parameter '", xPar.InnerText, "'"));
								XmlNode testelem = ResultDoc.DocumentElement.AppendChild(ResultDoc.CreateElement("test"));
								testelem.InnerXml = args[i];
								ResultDoc.DocumentElement.RemoveChild(testelem);
								thisok = AddSqlPar(args[i], xPar.InnerText, System.Convert.ToInt32(xPar.SelectSingleNode("@length").InnerText));
								break;
							case "string":
								if (xPar.SelectSingleNode("@length") == null)
									throw new Exception(String.Concat("Definition must specify length for string parameter '", xPar.InnerText, "'"));
								thisok = AddSqlPar(args[i], xPar.InnerText, System.Convert.ToInt32(xPar.SelectSingleNode("@length").InnerText));
								break;
							case "token":
								if (args[i] == "")	// rather set error explicitly??
									throw new Exception("Cannot have null token");
								else
									thisok = AddSqlPar(args[i], xPar.InnerText);
								break;
							case "output":
								thisok = AddSqlPar(xPar.InnerText);
								break;
							default:
								thisok = AddSqlPar(System.Convert.ToInt32(args[i]), xPar.InnerText);
								break;
						}
						if (!thisok)
							isok = false;
					}
					if (isok) {
						XmlElement callEl = (XmlElement) def.SelectSingleNode("call");
						if (callEl.GetAttribute("type") == "sproc" && callEl.GetAttribute("nonquery") == "yes") {
							xCmd.ExecuteNonQuery();
						} else {
							SqlDataReader xRdr = xCmd.ExecuteReader(CommandBehavior.CloseConnection);
							AddResults(def, ResultDoc, xRdr);
							xRdr.Close();
							AddParameters(def, ResultDoc);
							if (wantreturn)
								AddError(ResultDoc);
						}
					}
					else {	// rather set error explicitly??
						throw new Exception("Error processing input parameters");
					}
				} catch (Exception exc) {
					XmlNode xBad = xServ.GetException(name);
					throw new x_exception(xBad.SelectSingleNode("@value").InnerText, String.Concat(xBad.InnerText, " - ", exc.Source, " - ", exc.Message, "[", exc.StackTrace, "]"));
				} finally {
					xdb.Close();
				}
			}	// will force a dispose of the connection
			return(ResultDoc);
		}
		
		/// <summary>
		/// Calls a number of methods (recurively)
		/// </summary>
		public XmlDocument CallMethods(XmlNode thisdef, params string[] args) {
			XmlDocument thisDoc = new XmlDocument();
			thisDoc.LoadXml(xServ.GetReturn(thisdef.SelectSingleNode("@name").InnerText));
			return(CallMethods(thisDoc, thisdef, args));
		}
		/// <summary>
		/// Calls a number of methods (recurively)
		/// </summary>
		public XmlDocument CallMethods(XmlDocument ResultDoc, XmlNode thisdef, params string[] args) {
			XmlDocument thisdoc;
			
			XmlNode resnode, parnode;
			// Get parent node name (to contain results from methods)
			XmlNodeList methList = thisdef.SelectNodes("//output/method");
			XmlNode methresult = thisdef.SelectSingleNode("//result[@default='yes']");
			string parent = methresult.SelectSingleNode("@parent").InnerText;
			// Add parent node to document
			resnode = ResultDoc.SelectSingleNode("//Result");
			XmlElement elem = ResultDoc.CreateElement(parent);
			parnode = resnode.AppendChild(elem);
			
			foreach (XmlNode meth in methList) {
				string methName = meth.SelectSingleNode("@name").InnerText;
				try {
					thisdoc = CallMethod(methName, args);
					resnode = thisdoc.SelectSingleNode("//" + meth.SelectSingleNode("@node").InnerText);
					parnode.InnerXml = parnode.InnerXml + resnode.InnerXml;
				} catch(x_exception exc) {	// if one CallMethod fails...?
					XmlNode xBad = xServ.GetException(((XmlElement)thisdef.ParentNode).GetAttribute("name"));
					throw new x_exception(xBad.SelectSingleNode("@value").InnerText, String.Concat("Method:", methName, ":: ", xBad.InnerText, " - ", exc.Source, " - ", exc.Message, "[", exc.StackTrace, "]"));
				} catch (Exception exc) {	// another type of exception - raise
					XmlNode xBad = xServ.GetException(((XmlElement)thisdef.ParentNode).GetAttribute("name"));
					throw new x_exception(xBad.SelectSingleNode("@value").InnerText, String.Concat(xBad.InnerText, " - ", exc.Source, " - ", exc.Message, "[", exc.StackTrace, "]"));
				}
			}
			return(ResultDoc);
		}
		#endregion
		
		#region Protected methods
		#endregion
				
		#region Private methods
		/// <overloads>Sets defaults on construction</overloads>
		private void setDefaults(string service) {
			xDoc = new XmlDocument();
			xDSN = ConfigurationManager.AppSettings["DefaultDSN"];
			xServ = new x_service(service);
		}
		private void setDefaults(HttpApplicationState app, string ServiceID) {
			setDefaults(new XmlDocument(), app, ServiceID);
		}
		private void setDefaults(XmlDocument result, HttpApplicationState app, string ServiceID) {
			xDoc = result;
			xDSN = ConfigurationManager.AppSettings["DefaultDSN"];
			xServ = (x_service)app.Get(ServiceID);
			if (xServ == null)
				throw(new Exception("x_service Application object does not exist"));
		}
		/// <overloads>Sets defaults on construction</overloads>
		private void loadMethod(string methodName) {
			isLoaded = false;
			name = methodName;
			xDef = xServ.GetDefintion(methodName);
			xDoc.LoadXml(xServ.GetReturn(methodName));
			xMod = xServ.GetModule(methodName);
			xType = xServ.GetCall(methodName);
			isLoaded = true;
		}
		private void loadMethod(string methodName, string token) {
			isLoaded = false;
			name = methodName;
			xDef = xServ.GetDefintion(methodName);
			Validate(token);
			if (isValid) {
				xDoc.LoadXml(xServ.GetReturn(methodName));
				xMod = xServ.GetModule(methodName);
				xType = xServ.GetCall(methodName);
				isLoaded = true;
			} else {
				throw new Exception("Validation error on loading");
			}
		}
		#endregion
				
		#region Private methods (pre version="1.0.0")
		/// <summary>
		/// Calls a method
		/// </summary>
		private XmlDocument CallMethod(string methname, params string[] args) {
			XmlNode methdef = xServ.GetDefintion(methname);
			/*
			XmlDocument call = new XmlDocument();
			call.LoadXml(methdef.OuterXml);
			return(call);
			*/
			return(Call(methdef, args));
		}
		
		/// <summary>
		/// Adds results from the recordset
		/// </summary>
		private void AddResults(XmlNode def, XmlDocument doc, SqlDataReader xRdr) {
			XmlNode newRec;
			XmlElement xRoot;
			string thisval, thispar, thisname;
			thisname = def.SelectSingleNode("@name").InnerText;
			string thistype = xServ.GetResultType(thisname);
			//addDebug(doc, "name", thisname);
			//addDebug(doc, "type", thistype);
			if (thistype == "set" || thistype == "csv") {
				XmlDocumentFragment xFrag = doc.CreateDocumentFragment();
				xRoot = (XmlElement)doc.SelectSingleNode(xMod);
				xFrag.InnerXml = xServ.GetResultSet(thisname, out thispar);
				// add a parent node (if defined)
				if (thispar != "") {
					XmlElement elem = doc.CreateElement(thispar);
					xRoot = (XmlElement)xRoot.AppendChild(elem);
				}
				// Read the record set and add child nodes defined by result
				if (thistype == "csv") {
					csvData = new StringBuilder();
					// Add first row to csv as names
					AddChildren(true, xFrag, xRdr);
					csvData.Append(String.Concat(csvDataLine.Remove(csvDataLine.LastIndexOf(", "), 2), "\n"));
					// Add subsequent rows as values
					while (xRdr.Read()) {
						csvDataLine = "";
						AddChildren(false, xFrag, xRdr);
						csvData.Append(String.Concat(csvDataLine.Remove(csvDataLine.LastIndexOf(", "), 2), "\n"));
					}
					XmlCDataSection cdata = doc.CreateCDataSection(csvData.ToString());
					xRoot.AppendChild(cdata);
				} else {
					while (xRdr.Read()) {
						newRec = xFrag.CloneNode(true);
						AddChildren(newRec, xRdr);
						xRoot.AppendChild(newRec);
					}
				}
			}
			else if (thistype == "values") {
				xRoot = (XmlElement)doc.SelectSingleNode(xMod);
				newRec = xServ.GetResultNode(thisname, "values");
				if (xRdr.Read()) {
					XmlElement xChild, xNew;
					for (int i=0; i < newRec.ChildNodes.Count; i++) {
						xChild = (XmlElement)newRec.ChildNodes.Item(i);
						switch(xChild.GetAttribute("type")){
							case "ordinal":
							case "attribute":
								thisval = xRdr.GetSqlValue(xRdr.GetOrdinal(xChild.InnerText)).ToString();
								xRoot.SetAttribute(xChild.Name, thisval);
								break;
							case "element":
								thisval = xRdr.GetSqlValue(xRdr.GetOrdinal(xChild.InnerText)).ToString();
								xNew = (XmlElement)xRoot.AppendChild(doc.ImportNode(xChild, true));
								xNew.RemoveAttribute("type");
								xNew.InnerText = thisval;
								break;
							default:
								thisval = "";
								break;
						}
					}
				}
			}
		}
		
		/// <summary>
		/// Adds any output parameters to the result
		/// </summary>
		private void AddParameters(XmlNode def, XmlDocument doc){
			XmlNode newRec;
			XmlElement xRoot;
			string thisname = def.SelectSingleNode("@name").InnerText;
			if (xServ.GetResultType(name) == "values") {
				xRoot = (XmlElement) doc.SelectSingleNode(xMod);
				newRec = xServ.GetResultNode(thisname, "values");
				XmlElement xChild;
				for (int i=0; i < newRec.ChildNodes.Count; i++) {
					xChild = (XmlElement)newRec.ChildNodes.Item(i);
					if (xChild.GetAttribute("type") == "parameter")
						xRoot.SetAttribute(xChild.Name, xCmd.Parameters["@" + xChild.InnerText].Value.ToString());
				}
			}
			else if (xServ.GetResultType(name) == "set") {
				XmlElement resElem = (XmlElement) xServ.GetResultNode(thisname, "set");
				string parent = resElem.GetAttribute("parent");
				if (parent != "") {
					string wantParams = resElem.GetAttribute("parameters");
					xRoot = (XmlElement) doc.SelectSingleNode(String.Concat("//", parent));
					if (wantParams == "yes")	// if parameters="yes" then write all input parameters to parent as attributes
						foreach (XmlNode xNode in xServ.GetInputs(thisname))
							xRoot.SetAttribute(xNode.InnerText, xCmd.Parameters["@" + xNode.InnerText].Value.ToString());
					else	// else just write output parameters to parent
						foreach (XmlNode xNode in xServ.GetInputs(thisname, "output"))
							xRoot.SetAttribute(xNode.InnerText, xCmd.Parameters["@" + xNode.InnerText].Value.ToString());
				}
			}
		}
		
		/// <summary>
		/// Adds any error messages to the result
		/// </summary>
		private void addDebug(string dbgnde, string dbgval) {
			addDebug(xDoc, dbgnde, dbgval);
		}
		
		private void addDebug(XmlDocument doc, string dbgnde, string dbgval) {
			XmlNode dbgnode = doc.SelectSingleNode("//Result");
			XmlElement elem = doc.CreateElement(dbgnde);
			elem.InnerText = dbgval;
			dbgnode.AppendChild(elem);
		}
		
		/// <summary>
		/// Adds any error messages to the result
		/// </summary>
		private void addError(XmlDocument doc, string errmsg, string errcde) {
			if (errcde != "0") {
				XmlNode errnode = xDef.SelectSingleNode("//result[@type='error'][@value='" + errcde + "']");
				if (errnode != null)
					errmsg = errnode.InnerText;
				
				// look for module level error codes?
				
				doc.SelectSingleNode("//ResultCode").InnerText = errcde;
				doc.SelectSingleNode("//Result/Description").InnerText = errmsg;
			}
		}
		
		/// <overloads>Adds an error</overloads>
		/// <summary>
		/// Adds a defined error messages (from the sproc) to the result
		/// </summary>
		/// <param name="doc">The document that contains the error</param>
		public void AddError(XmlDocument doc) {
			string errormsg = "undefined error";
			string errorcde = xCmd.Parameters["@ReturnValue"].Value.ToString();
			addError(doc, errormsg, errorcde);
		}
		/// <summary>
		/// Adds a 'undefined error' message to the result
		/// </summary>
		public void AddError() {
			string errormsg = "undefined error";
			string errorcde = xCmd.Parameters["@ReturnValue"].Value.ToString();
			addError(xDoc, errormsg, errorcde);
		}
		/// <summary>
		/// Adds an error messages to the result via the error code
		/// </summary>
		/// <param name="error">An error value</param>
		public void AddError(int error) {
			string errormsg = "undefined error";
			string errorcde = error.ToString();
			addError(xDoc, errormsg, errorcde);
		}
		/// <summary>
		/// Adds an error messages to the result for a specified error code and message
		/// </summary>
		/// <param name="error">An error value</param>
		/// <param name="errormsg">An error message</param>
		public void AddError(int error, string errormsg) {
			addError(xDoc, errormsg, error.ToString());
		}
		/// <overloads>Adds values from the fields in the recordset</overloads>
		/// <summary>Adds values to child nodes defined in the result set xml</summary>
		private void AddChildren(XmlNode thisnode, SqlDataReader xRdr) {
			XmlNode nullnode;
			int ord;
			if(thisnode.HasChildNodes) {
				bool wantnull = false;
				nullnode = thisnode.SelectSingleNode("@null");
				if (nullnode != null) {
					wantnull = (nullnode.InnerText == "yes")? true : false;
					//thisnode.RemoveChild(nullnode);
				}
				foreach (XmlNode xChild in thisnode.ChildNodes) {
					if (xChild.NodeType == XmlNodeType.Element && xChild.Name == "xhtml") {	// special case
							ord = xRdr.GetOrdinal(xChild.InnerText);
							if (xRdr.IsDBNull(ord) && !wantnull)
								thisnode.RemoveChild(xChild);
							else
								xChild.InnerXml = xRdr.GetSqlValue(ord).ToString();
					} else if (xChild.NodeType == XmlNodeType.Text || xChild.NodeType == XmlNodeType.Attribute) {
						try {
							ord = xRdr.GetOrdinal(xChild.Value);
							if (xRdr.IsDBNull(ord) && !wantnull)
								thisnode.RemoveChild(xChild);
							else
								xChild.Value = xRdr.GetSqlValue(ord).ToString();
						} catch (IndexOutOfRangeException) { 
							continue; 
						} catch {
							throw new Exception("Error on node child, field:" + xChild.Value);
						}
					}
					else
						AddChildren(xChild, xRdr);
				}
			}
			if (thisnode.Attributes != null) {
				foreach (XmlAttribute xAttr in thisnode.Attributes) {
					try {
						ord = xRdr.GetOrdinal(xAttr.Value);
						xAttr.Value = xRdr.GetSqlValue(ord).ToString();
					} catch (IndexOutOfRangeException) { 
						continue; 
					} catch {
						throw new Exception("Error on attribute child, field:" + xAttr.Value);
					}
				}
			}
		}
		/// <summary>Adds values to a csv string from child nodes defined in the result set xml</summary>
		private void AddChildren(bool first, XmlNode thisnode, SqlDataReader xRdr) {
			XmlNode nullnode;
			bool wantnull = false;
			nullnode = thisnode.SelectSingleNode("@null");
			if (nullnode != null)
				wantnull = (nullnode.InnerText == "yes")? true : false;
			if(thisnode.HasChildNodes) {
				foreach (XmlNode xChild in thisnode.ChildNodes) {
					if (xChild.NodeType == XmlNodeType.Text || xChild.NodeType == XmlNodeType.Attribute)
						if (!first)
						 	addChild(xRdr, xChild, wantnull);
						else 
							addChild(xChild);
					else
						AddChildren(first, xChild, xRdr);
				}
			}
			if (thisnode.Attributes != null) {
				foreach (XmlAttribute xAttr in thisnode.Attributes)
					if (!first)
						addChild(xRdr, xAttr, wantnull);
					else
						addChild(xAttr);
			}
		}
		/// <overloads>Adds values to a csv string from a child node</overloads>
		/// <summary>Adds value from text and attribute node</summary>
		private void addChild(SqlDataReader rdr, XmlNode node, bool wantnull) {
			try {
				int ord = rdr.GetOrdinal(node.Value);
				if (rdr.IsDBNull(ord) && !wantnull)
					csvDataLine = String.Concat(csvDataLine, ", ");
				else
					csvDataLine = String.Concat(csvDataLine, rdr.GetSqlValue(ord).ToString(), ", ");
			} catch (IndexOutOfRangeException) { 
			} catch {
				throw new Exception("Error on node child, field:" + node.Value);
			}
		}
		/// <summary>Adds value from attribute node</summary>
		private void addChild(SqlDataReader rdr, XmlAttribute attr, bool wantnull) {
			try {
				int ord = rdr.GetOrdinal(attr.Value);
				if (rdr.IsDBNull(ord) && !wantnull)
					csvDataLine = String.Concat(csvDataLine, ", ");
				else
					csvDataLine = String.Concat(csvDataLine, rdr.GetSqlValue(ord).ToString(), ", ");
			} catch (IndexOutOfRangeException) { 
			} catch {
				throw new Exception("Error on attribute child, field:" + attr.Value);
			}
		}
		/// <summary>Adds name from text and attribute node</summary>
		private void addChild(XmlNode node) {
			csvDataLine = String.Concat(csvDataLine, node.Name, ", ");
		}
		/// <summary>Adds name from attribute node</summary>
		private void addChild(XmlAttribute attr) {
			csvDataLine = String.Concat(csvDataLine, attr.Name, ", ");
		}
		/// <summary>
		/// Adds the (default) return parameter to a stored procedure call (integer)
		/// </summary>
		private bool AddSqlPar() {
			try {
				SqlParameter par = new SqlParameter("@ReturnValue", SqlDbType.Int);
				par.Direction = ParameterDirection.ReturnValue;
				xCmd.Parameters.Add(par);
				return(true);
			}
			catch {
				return(false);
			}
		}
		/// <summary>
		/// Adds an parameter to a stored procedure call (output - integer)
		/// </summary>
		private bool AddSqlPar(string parname) {
			try {
				SqlParameter par = new SqlParameter("@" + parname, SqlDbType.Int);
				par.Direction = ParameterDirection.Output;
				xCmd.Parameters.Add(par);
				return(true);
			}
			catch {
				return(false);
			}
		}
		/// <summary>
		/// Adds an parameter to a stored procedure call (output - string)
		/// </summary>
		private bool AddSqlPar(string parname, int parlen) {
			try {
				SqlParameter par = new SqlParameter("@" + parname, SqlDbType.VarChar, parlen);
				par.Direction = ParameterDirection.Output;
				xCmd.Parameters.Add(par);
				return(true);
			}
			catch {
				return(false);
			}
		}
		/// <summary>
		/// Adds an parameter to a stored procedure call (integer)
		/// </summary>
		private bool AddSqlPar(int parval, string parname) {
			try {
				SqlParameter par = new SqlParameter("@" + parname, SqlDbType.Int);
				par.Value = parval;
				xCmd.Parameters.Add(par);
				return(true);
			}
			catch {
				return(false);
			}
		}
		/// <summary>
		/// Adds an parameter to a stored procedure call (string)
		/// </summary>
		private bool AddSqlPar(string parval, string parname, int parlen) {
			try {
				SqlParameter par = new SqlParameter("@" + parname, SqlDbType.VarChar, parlen);
				par.Value = parval;
				xCmd.Parameters.Add(par);
				return(true);
			}
			catch {
				return(false);
			}
		}
		/// <summary>
		/// Adds an parameter to a stored procedure call (uniqueidentifier)
		/// </summary>
		private bool AddSqlPar(string parval, string parname) {
			Guid tok;
			try {
				// best way to trap that value not valid token...
				try { tok = new Guid(parval); }
				catch { return(false); }
				SqlParameter par = new SqlParameter("@" + parname, SqlDbType.VarChar, 65);
				par.Value = tok.ToString();
				xCmd.Parameters.Add(par);
				return(true);
			}
			catch {
				return(false);
			}
		}
		/// <summary>
		/// Checks if the method requires validation
		/// </summary>
		private bool RequireValidation() {
			reqValidation = (xDef.SelectSingleNode("validate") == null)? false : true;
			return(reqValidation);
		}
		
		/// <summary>
		/// Does the Validation (if required)
		/// </summary>
		private bool Validate(string Token) {
			isValid = false;
			XmlElement thisdef = (XmlElement)xDef.SelectSingleNode("validate");
			if (thisdef == null)
				isValid = true;
			else {
				x_method m_valid = new x_method(xServ.GetDefintionFile());
				m_valid.Load(thisdef.InnerText);
				xDoc = m_valid.Call(Token, thisdef.GetAttribute("service"), thisdef.GetAttribute("security"));
				isValid = (xDoc.SelectSingleNode("//ResultCode").InnerText == "0");
			}
			return(isValid);
		}
		
		/// <summary>
		/// Adds an element to the result xml
		/// </summary>
		private void AddResult(string elname, string elval) {
			if (isLoaded) {
				XmlElement newElem = xDoc.CreateElement(elname);
       			newElem.InnerText = elval;
 				XmlNode resNode = xDoc.SelectSingleNode("//Result");
				resNode.AppendChild(newElem);
			}
		}
		#endregion
	}
}
